/**
    Copyright 2015 Table Rider
    By: Christoffer Lindström & Daniel Westerlund
*/

#include "ComClient.h"

ComClient::ComClient()
{

}
ComClient::~ComClient()
{

}

/**
Description:
    Initializes the client. Creates a socket, binds it to a port and connects to a remote server via IP
Pre-condition:
    Arguments: const char* ipnumber, int portnumber
Post-condition:
    Socket is created, socket is connected to server, the returned const char* delivers "Init Complete"
Return:
if success:
    "Init Complete"
else:
    "Winsocket init failed" Windows may return this errorcode
    "Could not create socket"
    "Invalid IP adress" Control the format of your IPnumber
    "Could not connect to server" Validate that you're calling the correct IP number of the server
Test cases:
1. Function call with invalid ip, (127.0.0.1 , no server on ip) => returns "could not connect to server"
2. Function call with invalid port, server running on ip (127.0.0.1, server port 4444, client 4443 => returns "could not connect to server"
3. Function call with server running on ip and port and listening for connections => returns "Init complete"

*/
const char* ComClient::init(const char* ip,int portnumber)
{
	//printf("IP:%s\tPort:%d\n", ip, portnumber);
    #ifdef _WIN32
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)//Initiates Winsock-socket
    {
        return "Winsocket init failed\n\0";
    }
    if((ComSocket = socket(AF_INET, SOCK_STREAM,0))==INVALID_SOCKET)//Creates Winsock-socket
    {
        return "Could not create socket\n\0";
    }
    #endif

    #ifdef __linux__
    ComSocket = socket(AF_INET,SOCK_STREAM,0);
    if(ComSocket ==-1)
    {
        return "Could not create socket failed\n\0";//Creates Unix-socket
    }
    #endif
    if(ip!='\0')
    {
        ipnumber = inet_addr(ip);
    }
    else return "invalid IP adress";

    //Sets the parameters for the server which is a "struct" inside the socketclass both Winsock and Unix
    server.sin_addr.s_addr = ipnumber;
    server.sin_family = AF_INET;
    server.sin_port = htons(portnumber);

    //Connect to remote server
    #ifdef __WIN32
    if(connect(ComSocket,(struct sockaddr*)&server, sizeof(server))==SOCKET_ERROR)
    {
        printf("Connect failed: %d\n", WSAGetLastError());
        return "Could not connect to server\n\0";
    }
    #elif __linux__
     if(connect(ComSocket,(struct sockaddr*)&server, sizeof(server))<0)
    {
        return "Could not connect to server\n\0";
    }
    #endif

    return "Init complete";
}

const char* ComClient::init(unsigned long ip,int portnumber)
{
    #ifdef _WIN32
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){
        return "Winsocket init failed\n\0";
    }
    if((ComSocket = socket(AF_INET, SOCK_STREAM,0))==INVALID_SOCKET){
        return "Could not create socket\n\0";
    }
    #endif

    #ifdef __linux__
    ComSocket = socket(AF_INET,SOCK_STREAM,0);
    if(ComSocket ==-1){
        return "Could not create socket failed\n\0";
    }
    #endif
    //if(ip!='\0')
    //{
        ipnumber = ip;
    //}
    //else return "invalid IP adress";

    server.sin_addr.s_addr = ipnumber;
    server.sin_family = AF_INET;
    server.sin_port = htons(portnumber);

    //Connect to remote server
    #ifdef __WIN32
    if(connect(ComSocket,(struct sockaddr*)&server, sizeof(server))==SOCKET_ERROR)
    {
        printf("Connect failed: %d\n", WSAGetLastError());
        return "Could not connect to server\n\0";
    }
    #elif __linux__
     if(connect(ComSocket,(struct sockaddr*)&server, sizeof(server))<0)
    {
        return "Could not connect to server\n\0";
    }
    #endif

    return "Init complete";
}


/**


Description:
    Sends a message to the ipnumber and port that was designated via the initfunction

Pre-case:
    Init is called and returns "Init complete"
    Argument: void* message, int length
    message is a message to be sent, length is the length of this message.
Post-case:
    Message is sent over socket to server

Returns:
    int -1 if the methods fails
    int 0 if method succeeded
    if system runs on Windows and fails you will also get "Send failed: " and WSAGetLastError, a Windows errorcode

Testcases:
1.  Function call without Init method => Returns -1
2.  Function call with wrong message size (Smaller than message, greater than message)=> Returns 0
3.  Function call with empty message => Returns 0
4.  Function call with right message and size => Returns 0
*/

int ComClient::send_msg(void *message, int length)
{
    #ifdef __linux__
    if(send(ComSocket, message,length,0) < 0)
    {
        return -1;
    }
    return 0;
    #elif _WIN32
    if(send(ComSocket, (const char*)message,length,0) == SOCKET_ERROR)
    {
        printf("Send failed: %d\n", WSAGetLastError());
        return -1;
    }
    return 0;
    #endif
}

/**
Description
    Retrieves the message from server, which is saved in a buffer
Pre-case
    Init is called and returns "Init complete"
    Arguments: NULL

Post-case
    Recieved message

Returns
    If success you will recieve the message
    else "Could not receive"
    if system runs on Windows and fails you will also get "Send failed: " and WSAGetLastError, a Windows errorcode

Testcases
1.  Function call without Init method =>    Returns "Could not receive"
2.  Function call without server send =>    Returns NULL array
*/


const char* ComClient::receive_msg()
{
    //Make sure the buffer is empty before receiving
    int x = 0;
    while(recv_msg[x] != '\0')
    {
        recv_msg[x] = '\0';
        x++;
    }

    #ifdef __linux__
    if(recv(ComSocket,recv_msg,2000,0)<0){
        return "Could not receive\n\0";
    }
    #elif _WIN32
    if(recv(ComSocket,recv_msg,2000,0)==SOCKET_ERROR){
        printf("recv failed: %d\n", WSAGetLastError());
        return "Could not receive\n\0";
    }
    #endif
    return recv_msg;
}
/**
Description
    Closes the connection and socket

Pre-case
    Init is called and returns "Init complete"
    Arguments: NULL

Post-case
    Sockets are closed

*/
void ComClient::close_connection()
{
    //Close the connection
    #ifdef __linux__
    close(ComSocket);
    #elif _WIN32
    closesocket(ComSocket);
    WSACleanup();
    #endif
}
